package com.atguigu.lease.web.app.service.impl;


import com.atguigu.lease.common.constants.RedisConstant;
import com.atguigu.lease.common.jwt.JwtUtil;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.common.springmvc.LeaseException;
import com.atguigu.lease.model.entity.UserInfo;
import com.atguigu.lease.model.enums.BaseStatus;
import com.atguigu.lease.web.app.service.LoginService;
import com.atguigu.lease.web.app.service.UserInfoService;
import com.atguigu.lease.web.app.vo.user.LoginVo;
import com.atguigu.lease.web.app.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private UserInfoService userInfoService;
    /**
     * 获取短信验证码
     * @param phone
     * 1. 设置key
     * 2. 判断有没有key
     *      2.1 有，判断过期了没有，没过期抛异常
     * 3. 过期了或没有key，创建一个key
     *      3.1 生成6位短信验证码
     *      3.2 将验证码存到redis中
     *      3.3 发送短信验证码
     */
    @Override
    public void sendCode(String phone) {
        //1. 设置key 【前缀+手机号】
        String key = RedisConstant.APP_LOGIN_PREFIX + phone;
        //2. 判断redis里面有没有这个key
        Boolean hasKey = redisTemplate.hasKey(key);
        //3. 如果有则说明验证码已经发送了，需要进行再一次判断
        if(hasKey){
            //检查key剩余的有效时间
            Long expire = redisTemplate.getExpire(key);
            //获取我们设置key的有效时间
            Integer appLoginCodeTtlSec = RedisConstant.APP_LOGIN_CODE_TTL_SEC;
            //获取间隔多少秒发送一次
            Integer appLoginCodeResendTimeSec = RedisConstant.APP_LOGIN_CODE_RESEND_TIME_SEC;
            //如果“获取我们设置key的有效时间” - “检查key剩余的有效时间” < 获取间隔多少秒发送一次,
            //则抛出"验证法发送过于频繁"异常
            if(appLoginCodeTtlSec - expire < appLoginCodeResendTimeSec){
                throw new LeaseException(ResultCodeEnum.APP_SEND_SMS_TOO_OFTEN);
            }
        }
        //4. 生成验证码，随机6位数字
        //方式一：
/*        StringBuilder stringBuilder = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            stringBuilder.append(random.nextInt(10));
        }*/
        //方式二：
        Random random = new Random();
        Integer num = random.nextInt(900000)+100000;
        String code = num.toString();
        //5. 将6位数字验证码由stringBuilder转成字符串，并在控制台打印输出验证码
//        String code = stringBuilder.toString();
        System.out.println("验证码 = " + code);//临时解决方案，短信发送服务目前无法实现
        //6. 将验证码存储到redis中[key,value,有效时间，时间单位]
        redisTemplate.opsForValue().set(key,code,RedisConstant.APP_LOGIN_CODE_TTL_SEC, TimeUnit.SECONDS);
        //7. 发送验证码【暂时没法实现】
    }

    /**
     * 登录功能
     * @param loginVo
     * @return
     */
    @Override
    public String login(LoginVo loginVo) {
        //拿前端传的手机号去redis取验证码与前端传来的验证码进行比对
        String code = (String) redisTemplate.opsForValue().get(RedisConstant.APP_LOGIN_PREFIX + loginVo.getPhone());
        //验证码如果为null或与redis验证码不相等则抛出"验证码错误"
        if(code == null || !code.equals(loginVo.getCode())){
            throw new LeaseException(ResultCodeEnum.APP_LOGIN_CODE_ERROR);
        }
        //验证码正确，进行登录或者注册
        //根据前端传来的手机号去数据库查询用户
        LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserInfo::getPhone,loginVo.getPhone());
        UserInfo userInfo = userInfoService.getOne(queryWrapper);
        //如果用户为null，说明还没有注册过，进行注册
        if (userInfo == null){
            userInfo = new UserInfo();
            userInfo.setPhone(loginVo.getPhone());//手机号
            userInfo.setAvatarUrl("http://www.baidu.com/img/bd_logo.png");//头像
            userInfo.setNickname("佚名" + loginVo.getPhone().substring(7));//名字
            userInfo.setStatus(BaseStatus.ENABLE);//将用户状态设置为正常开启
            userInfoService.save(userInfo);
        }
        //如果用户不为null，为登录，判断用户是否可用，不可用抛异常
        if(userInfo.getStatus() == BaseStatus.DISABLE){
            throw new LeaseException(ResultCodeEnum.APP_ACCOUNT_DISABLED_ERROR);
        }
        //可用，就通过jwt创建一个token返回给前端
        String token = JwtUtil.createToken(userInfo.getId(), userInfo.getPhone());
        return token;
    }

    /**
     * 获取登录用户信息
     * @param accessToken
     * @return
     */
    @Override
    public UserInfoVo info(String accessToken) {
        //解析token【头部、负载、签名】
        Integer userId = (Integer) JwtUtil.parseToken(accessToken).get("userId");
        //根据userId查询用户
        UserInfo userInfo = userInfoService.getById(userId);
        UserInfoVo userInfoVo = new UserInfoVo(userInfo.getNickname(), userInfo.getAvatarUrl());
        return userInfoVo;
    }
}
